using System.Collections.Generic;
using System.Linq;
using Irony.Ast;
using Irony.Parsing;

namespace Flit
{
    /// <summary>
    /// The root AST node of Flit
    /// </summary>
    public class Graph : IAstNodeInit
    {
        /// <summary>
        /// Called by Irony
        /// </summary>
        /// <param name="context"></param>
        /// <param name="parseNode"></param>
        public void Init(ParsingContext context, ParseTreeNode parseNode)
        {
            Items = parseNode.Descendants().Select(x => x.AstNode).OfType<GraphItem>().ToList();

            //add any implicit states
            var missingStateIdentifiers =
                Transitions
                    .Select(x => x.FromIdentifier)
                    .Concat(Transitions.Select(x => x.ToIdentifier))
                    .Distinct()
                    .Except(States.Select(x => x.Identifier))
                    .Select(s => new State
                                     {
                                         Identifier = s,
                                         IsImplicit = true,
                                         Label = new Label { Name = s }
                                     })
                    .Cast<GraphItem>()
                    .ToList();

            Items.AddRange(missingStateIdentifiers);

            foreach (var item in Items)
            {
                item.Graph = this;
            }
        }

        private List<GraphItem> Items { get; set; }

        /// <summary>
        /// All of the states that have been defined in this fluent interface graph, including any implicit states 
        /// (states that were not declared, but were used in a transition)
        /// </summary>
        public IEnumerable<State> States { get { return Items.OfType<State>(); } }

        /// <summary>
        /// All of the transitions that are declared in this fluent interface graph
        /// </summary>
        public IEnumerable<Transition> Transitions { get { return Items.OfType<Transition>(); } }

        #region CodeGen helpers


        /// <summary>
        /// Get all the edges that leave a particular state
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public IEnumerable<Transition> EdgesFrom(State state)
        {
            return Transitions.Where(x => x.FromIdentifier == state.Identifier);
        }

        /// <summary>
        /// Get a state by its identifier
        /// </summary>
        /// <param name="identifier"></param>
        /// <returns></returns>
        public State StateByIdentifier(string identifier)
        {
            return States.Single(x => x.Identifier == identifier);
        }

        #endregion


    }
}